use clap::Parser;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use wang_utils::core::resolve_file_path;

/// CHANGELOG生成工具
#[derive(Parser, Debug, Clone, Serialize, Deserialize)]
#[command(long_about)]
pub struct CliArgs {
    /// 指定版本号，强制使用这个版本。
    ///
    /// 例如："wlog -v v1.3.5"执行之后，假设当前是v2.6.5，新生成的是v1.3.5，不会遵循规则
    #[arg(long, short)]
    pub version: Option<String>,
    /// 指定生成tag类型。内置beta和alpha两个tag，其它的需要用-t手动指定。
    ///
    /// 例如："wlog -t test"执行之后，假设当前是v1.0.0，新生成的是v1.0.0-test.0，下次是v1.0.0-test.1
    #[arg(long, short)]
    pub tag: Option<String>,
    /// 快速指定tag为beta，相当于 "wlog -t beta"。
    ///
    /// 执行之后，假设当前是v1.0.0，那么新生成的是v1.0.0-beta.0，下次是v1.0.0-beta.1
    #[arg(long, default_value = "false")]
    pub beta: bool,
    /// 快速指定tag为alpha，相当于 "wlog -t alpha"。
    ///
    /// 执行之后，假设当前是v1.0.0，那么新生成的是v1.0.0-alpha.0，下次是v1.0.0-alpha.1
    #[arg(long, default_value = "false")]
    pub alpha: bool,
    /// 指定git路径，在哪个路径读取git提交记录。默认为当前目录
    ///
    /// 例如："wlog -p ~/Downloads/test-folder"，注意这个路径下必须有.git文件夹，否则会报错。
    #[arg(long, short)]
    pub path: Option<String>,
    /// 指定CHANGELOG.md输出路径，在哪个路径生成CHANGELOG.md。默认生成的名称为：CHANGELOG.md。
    ///
    /// 例如："wlog -o ~/Downloads/log.md"
    #[arg(long, short)]
    pub output: Option<String>,
    /// 只生成changelog，不进行git提交
    #[arg(default_value = "false", long, visible_alias = "sc")]
    pub skip_commit: bool,
    /// 反转提交信息的顺序。默认是从上到下，时间点从最旧到最新，加上这个参数之后会反过来
    #[arg(default_value = "false", long, visible_alias = "rc")]
    pub rev_commit: bool,
    /// 指定规则配置文件路径。可以指定生成的title、description，以及不同类型对应的文字。
    ///
    /// 默认会读取当前目录的".versionrc"、".versionrc.json"、 ".version.json"这些文件。
    ///
    /// 配置文件示例：<https://gitee.com/consolelog/wang-changelog/raw/master/tests/test_config/config2.json>
    #[arg(long, short = 'f')]
    pub config_file: Option<String>,
    /// 生成规则配置文件，提供给用户自行修改，此行为不会生成changelog。默认在当前目录生成文件.versionrc
    #[arg(default_value = "false", long, visible_alias = "gc")]
    pub generate_config: bool,
    /// 生成CHANGELOG最顶部标题，默认为“更新日志”
    ///
    /// 可以在config-file中配置
    #[arg(long)]
    pub title: Option<String>,
    /// 生成CHANGELOG标题下面的介绍文字，默认为“该日志由wang-changelog生成，详情见 https://gitee.com/consolelog/wang-changelog”
    ///
    /// 可以在config-file中配置
    #[arg(long)]
    pub desc: Option<String>,
}

impl CliArgs {
    pub fn new() -> Self {
        Self {
            version: None,
            tag: None,
            beta: false,
            alpha: false,
            path: None,
            output: None,
            skip_commit: false,
            rev_commit: false,
            config_file: None,
            generate_config: false,
            title: None,
            desc: None,
        }
    }
    pub fn resolve(&mut self) {
        // 解析应用在哪个路径
        self.resolve_path();
        // 解析输出CHANGELOG.md到哪个路径
        self.resolve_output();
        // 解析规则配置文件
        self.resolve_config_file();
    }
    pub fn resolve_path(&mut self) {
        let path = if let Some(path) = &self.path {
            path.clone()
        } else {
            ".".to_string()
        };
        if let Ok(path) = resolve_file_path(&path) {
            self.path = Some(path.to_str().unwrap().to_string());
        }
    }
    pub fn resolve_output(&mut self) {
        let output = if let Some(output) = &self.output {
            output.clone()
        } else {
            let path = self.path.as_ref().unwrap();
            let path = PathBuf::from(path);
            path.join("CHANGELOG.md").to_str().unwrap().to_string()
        };
        if let Ok(output) = resolve_file_path(&output) {
            self.output = Some(output.to_str().unwrap().to_string());
        }
    }
    pub fn resolve_config_file(&mut self) {
        let config_file = if let Some(config_file) = &self.config_file {
            config_file.clone()
        } else {
            let path = self.path.as_ref().unwrap();
            let path = PathBuf::from(&path);
            if path.join(".versionrc").exists() {
                path.join(".versionrc").to_str().unwrap().to_string()
            } else if path.join(".versionrc.json").exists() {
                path.join(".versionrc.json").to_str().unwrap().to_string()
            } else if path.join(".version.json").exists() {
                path.join(".version.json").to_str().unwrap().to_string()
            } else {
                path.join(".versionrc").to_str().unwrap().to_string()
            }
        };
        if let Ok(config_file) = resolve_file_path(&config_file) {
            self.config_file = Some(config_file.to_str().unwrap().to_string());
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::utils::test_utils::{setup_test_folder, teardown_git};

    #[test]
    fn test_cli_args() -> anyhow::Result<()> {
        let test_folder = setup_test_folder();
        assert!(test_folder.starts_with("unit_test_folder"));
        let mut args = CliArgs::new();
        args.path = Some(test_folder.to_string());
        args.resolve();
        assert!(!args.path.unwrap().starts_with("unit_test_folder"));
        teardown_git(&test_folder);
        Ok(())
    }
}
